/**
 * ORIPA - Origami Pattern Editor 
 * Copyright (C) 2005-2009 Jun Mitani http://mitani.cs.tsukuba.ac.jp/

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package oripa.geom;

import java.awt.Color;
import java.awt.geom.GeneralPath;
import java.util.ArrayList;
import javax.vecmath.Vector2d;
import javax.vecmath.Vector3d;
import oripa.Condition3;
import oripa.Condition4;
import oripa.ORIPA;


public class OriFace {

    public ArrayList<OriHalfedge> halfedges = new ArrayList<>();
    public GeneralPath outline = new GeneralPath();
    public GeneralPath preOutline = new GeneralPath();
    public boolean selected = false;
    public boolean faceFront = true;
    public Color color;
    public boolean tmpFlg = false;
    public int z_order = 0;
    public int tmpInt2 = 0;
    public int tmpInt = 0;
    public boolean hasProblem = false;
    public boolean alreadyStacked = false;
    public ArrayList<TriangleFace> triangles = new ArrayList<>();
    public int intColor;
    public ArrayList<Condition4> condition4s = new ArrayList<>();
    public ArrayList<Condition3> condition3s = new ArrayList<>();
    public ArrayList<Integer> condition2s = new ArrayList<>();

    public OriFace() {
        int r = (int) (Math.random() * 255);
        int g = (int) (Math.random() * 255);
        int b = (int) (Math.random() * 255);
        color = new Color(r, g, b);
    }

    public void trianglateAndSetColor(boolean bUseColor, boolean bFlip) {
        triangles.clear();

        double min_x = Double.MAX_VALUE;
        double max_x = -Double.MAX_VALUE;
        double min_y = Double.MAX_VALUE;
        double max_y = -Double.MAX_VALUE;

        for (OriHalfedge he : halfedges) {
            min_x = Math.min(min_x, he.vertex.p.x);
            max_x = Math.max(max_x, he.vertex.p.x);
            min_y = Math.min(min_y, he.vertex.p.y);
            max_y = Math.max(max_y, he.vertex.p.y);
        }

        double faceWidth = Math.sqrt((max_x - min_x) * (max_x - min_x) + (max_y - min_y) * (max_y - min_y));

        for (OriHalfedge he : halfedges) {
            double val = 0;
            if (he.edge.type == OriLine.TYPE_RIDGE) {
                val += 1;
            } else if (he.edge.type == OriLine.TYPE_VALLEY) {
                val -= 1;
            }

            if (he.prev.edge.type == OriLine.TYPE_RIDGE) {
                val += 1;
            } else if (he.prev.edge.type == OriLine.TYPE_VALLEY) {
                val -= 1;
            }

            double vv = ((double) val + 2) / 4.0;
            double v = (0.75 + vv * 0.25);
            
            v *= 0.9 + 0.15 * (Math.sqrt((he.vertex.p.x - min_x) * (he.vertex.p.x - min_x)
                    + (he.vertex.p.y - min_y) * (he.vertex.p.y - min_y)) / faceWidth);
            
            v = Math.min(1, v);

            if (bUseColor) {
                if (true) {
                    if (faceFront ^ bFlip) {
                        he.vertexColor.set(v * 0.7, v * 0.7, v);
                    } else {
                        he.vertexColor.set(v, v * 0.8, v * 0.7);
                    }
                } else {
                    if (faceFront ^ bFlip) {
                        he.vertexColor.set(v, v * 0.6, v * 0.6);
                    } else {
                        he.vertexColor.set(v, v, v * 0.95);
                    }

                }
            } else {
                he.vertexColor.set(v, v, v * 0.95);
            }
        }

        int heNum = halfedges.size();
        OriHalfedge startHe = halfedges.get(0);
        for (int i = 1; i < heNum - 1; i++) {
            TriangleFace tri = new TriangleFace(this);
            tri.v[0].p = new Vector2d(startHe.vertex.p);
            tri.v[1].p = new Vector2d(halfedges.get(i).vertex.p);
            tri.v[2].p = new Vector2d(halfedges.get(i + 1).vertex.p);

            tri.v[0].color = new Vector3d(startHe.vertexColor);
            tri.v[1].color = new Vector3d(halfedges.get(i).vertexColor);
            tri.v[2].color = new Vector3d(halfedges.get(i + 1).vertexColor);

            tri.v[0].uv = new Vector2d(startHe.vertex.preP.x / ORIPA.doc.size + 0.5,
                    startHe.vertex.preP.y / ORIPA.doc.size + 0.5);
            tri.v[1].uv = new Vector2d(halfedges.get(i).vertex.preP.x / ORIPA.doc.size + 0.5,
                    halfedges.get(i).vertex.preP.y / ORIPA.doc.size + 0.5);
            tri.v[2].uv = new Vector2d(halfedges.get(i + 1).vertex.preP.x / ORIPA.doc.size + 0.5,
                    halfedges.get(i + 1).vertex.preP.y / ORIPA.doc.size + 0.5);
            triangles.add(tri);
        }
    }

    public void makeHalfedgeLoop() {
        int heNum = halfedges.size();
        for (int i = 0; i < heNum; i++) {
            OriHalfedge pre_he = halfedges.get((i - 1 + heNum) % heNum);
            OriHalfedge he = halfedges.get(i);
            OriHalfedge nxt_he = halfedges.get((i + 1) % heNum);

            he.next = nxt_he;
            he.prev = pre_he;
        }
    }

    public void printInfo() {
        System.out.println("OriFace");
        for (OriHalfedge he : halfedges) {
            System.out.println(he.vertex.p);
        }
    }
    
    public void setOutline() {
        outline.reset();
        outline.moveTo((float) (halfedges.get(0).positionForDisplay.x), (float) (halfedges.get(0).positionForDisplay.y));
        for (int i = 1; i < halfedges.size(); i++) {
            outline.lineTo((float) (halfedges.get(i).positionForDisplay.x), (float) (halfedges.get(i).positionForDisplay.y));
        }
        outline.closePath();
    }

    public void setPreOutline() {
        preOutline.reset();
        Vector2d centerP = new Vector2d();
        for (OriHalfedge he : halfedges) {
            centerP.add(he.vertex.preP);
        }
        centerP.scale(1.0 / halfedges.size());
        double rate = 0.5;

        preOutline.moveTo((float) (halfedges.get(0).vertex.preP.x * rate + centerP.x * (1.0 - rate)),
                (float) (halfedges.get(0).vertex.preP.y * rate + centerP.y * (1.0 - rate)));
        for (int i = 1; i < halfedges.size(); i++) {
            preOutline.lineTo((float) (halfedges.get(i).vertex.preP.x * rate + centerP.x * (1.0 - rate)),
                    (float) (halfedges.get(i).vertex.preP.y * rate + centerP.y * (1.0 - rate)));
        }
        preOutline.closePath();
    }

    public Vector2d getCenter() {
        Vector2d centerVec = new Vector2d();
        for (OriHalfedge he : halfedges) {
            centerVec.add(he.vertex.preP);
        }
        centerVec.scale(1.0 / halfedges.size());
        return centerVec;
    }
}
